
package projbd;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.math.BigInteger;
import java.sql.Statement;
import java.util.Collections;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;


public class XMLParser extends DefaultHandler {

    BigInteger numberTags = new BigInteger("0");
    
    private XMLReader xr;

    private String currentDeweyId = "1";
    private int currentPathId = 1;
    private String currentText = new String();
    private Integer currentLevel = 1;
    private Statement statement;
    private boolean ascending = true;
    
    private static final boolean TAG = true;
    private static final boolean TEXT = false;
    private boolean lastCall = TAG;

    private Writer statementsFile;

    private Stack<Integer> deweyStack = new Stack<Integer>();
    private int numberRows = 0;
    StringBuilder sqlStatement = new StringBuilder();
    
    public Statement getStatement() {
        return statement;
    }

    public void setStatement(Statement statement) {
        this.statement = statement;
    }

    public XMLParser() throws UnsupportedEncodingException, FileNotFoundException {
        super();
        statementsFile = new OutputStreamWriter(new FileOutputStream("sql/statements.sql"), "UTF-8");
    }

    @Override
    public void startDocument() throws SAXException {
        System.out.println("start document");
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.println("end document");

        if (!(sqlStatement.toString()).isEmpty() && (sqlStatement != null)) {
            try {
                statementsFile.write(sqlStatement.toString());
            } catch (IOException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        try {
            statementsFile.close();
        } catch (IOException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private String getFatherDewey() {
        Stack<Integer> ds = (Stack<Integer>) deweyStack.clone();
        ds.pop();
        Collections.reverse(ds);
        StringBuilder dewey = new StringBuilder();
        while (!ds.empty()) {
            Integer i = ds.pop();
            dewey = dewey.append(i);
            dewey = dewey.append(".");
        }
        return dewey.toString().substring(0, dewey.length() - 1);        
    }    
    
    private String constructDewey() {
        Stack<Integer> ds = (Stack<Integer>) deweyStack.clone();
        Collections.reverse(ds);
        StringBuilder dewey = new StringBuilder();
        while (!ds.empty()) {
            Integer i = ds.pop();
            dewey = dewey.append(i);
            dewey = dewey.append(".");
        }
        return dewey.toString().substring(0, dewey.length() - 1);
    }

    public String lines(String path) throws FileNotFoundException, IOException {
        File f = new File(path);
        BufferedReader input =  new BufferedReader(new FileReader(f));

        String line;
        boolean print = false;
        while (input.ready()) {
            line = input.readLine();

            if (line.contains("(-)-("))
                print = true;

            if (print) System.out.println(line);
            numberTags = numberTags.add(BigInteger.ONE);
        }
        return numberTags.toString();
    }

    @Override
    public void characters(char ch[], int start, int length) {
        
        numberTags = numberTags.add(BigInteger.ONE);
        numberRows++;
        
        String text = new String(ch, start, length);
        // text = text.trim();

        if (!text.isEmpty()) {
            text = text.replaceAll("!", ".");
            text = text.replaceAll("\\\\", "/");
            text = text.replaceAll("\n", " ");

            if (lastCall == TAG) {
                currentText = text;
            } else if (lastCall == TEXT) {
                currentText = currentText + text;
            }
            lastCall = TEXT;
        }
    }
    
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts) {
        
        numberTags = numberTags.add(BigInteger.ONE);
        numberRows++;
       
        String value = "";
        
	if ("".equals (uri)) {
            value = qName;
        } else {
            value = uri + name;
        }
        
        if (lastCall == TEXT) {
            if (!currentText.isEmpty()) {

                if (!ascending) {
                    Integer currentIndex = deweyStack.pop();
                    currentIndex++;
                    deweyStack.push(currentIndex);
                } else {
                    deweyStack.push(1);
                    ascending = false;
                }
                String oldDeweyId = getFatherDewey();
                currentDeweyId = constructDewey();

                sqlStatement.append(currentDeweyId);
                sqlStatement.append("!");
                sqlStatement.append(currentText);
                sqlStatement.append("!");
                sqlStatement.append("#null!text!");
                sqlStatement.append(oldDeweyId);
                sqlStatement.append("!");
                sqlStatement.append(currentPathId);
                sqlStatement.append("\n");

                try {
                    if (numberRows >= 500) {
                        statementsFile.write(sqlStatement.toString());
                        sqlStatement = new StringBuilder();
                        numberRows = 0;
                        System.out.println(numberTags);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
                }

                currentPathId++;
            }
        } 
        
        if ((lastCall == TAG) || (value != null)) {

            // go one level deeper -> child node's dewey code is fatherscode.i
            // (i the order of the child amongst siblings)

            if (!ascending) {
                Integer currentIndex = deweyStack.pop();
                currentIndex++;
                deweyStack.push(currentIndex);
                ascending = true;
            } else {
                deweyStack.push(1);
            }

            String oldDeweyId;
            if (currentLevel > 1) {
                oldDeweyId = getFatherDewey();
            } else {
                oldDeweyId = null;
            }

            currentDeweyId = constructDewey();

            String attributes = new String();
            if (atts != null) {
                int length = atts.getLength();

                int j;
                for (j = 0; j <= length - 1; j++) {
                    String currentAttName = atts.getLocalName(j);
                    String currentAttContent = atts.getValue(j);

                    attributes = attributes + currentAttName + "=" + currentAttContent + " ";
                }
            }

            if (oldDeweyId != null) {
                if (attributes.isEmpty()) {
                    sqlStatement.append(currentDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(value);
                    sqlStatement.append("!");
                    sqlStatement.append("#null!tag!");
                    sqlStatement.append(oldDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(currentPathId);
                    sqlStatement.append("\n");
                } else {
                    sqlStatement.append(currentDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(value);
                    sqlStatement.append("!");
                    sqlStatement.append(attributes);
                    sqlStatement.append("!tag!");
                    sqlStatement.append(oldDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(currentPathId);
                    sqlStatement.append("\n");
                }
            } else {
                if (attributes.isEmpty()) {
                    sqlStatement.append(currentDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(value);
                    sqlStatement.append("!");
                    sqlStatement.append("#null!tag!#null!");
                    sqlStatement.append(currentPathId);
                    sqlStatement.append("\n");
                } else {
                    sqlStatement.append(currentDeweyId);
                    sqlStatement.append("!");
                    sqlStatement.append(value);
                    sqlStatement.append("!");
                    sqlStatement.append(attributes);
                    sqlStatement.append("!tag!#null!");
                    sqlStatement.append(currentPathId);
                    sqlStatement.append("\n");
                }
            }

            try {
                if (numberRows >= 500) {
                    statementsFile.write(sqlStatement.toString());
                    sqlStatement = new StringBuilder();
                    numberRows = 0;
                    System.out.println(numberTags);
                }
            } catch (IOException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        currentLevel++;
        currentPathId++;
        
        lastCall = TAG;
    }

    @Override
    public void endElement(String uri, String name, String qName) {
        
        if (lastCall == TEXT) {
            if (!currentText.isEmpty()) {

                if (!ascending) {
                    Integer currentIndex = deweyStack.pop();
                    currentIndex++;
                    deweyStack.push(currentIndex);
                } else {
                    deweyStack.push(1);
                    ascending = false;
                }
                String oldDeweyId = getFatherDewey();
                currentDeweyId = constructDewey();

                sqlStatement.append(currentDeweyId);
                sqlStatement.append("!");
                sqlStatement.append(currentText);
                sqlStatement.append("!");
                sqlStatement.append("#null!text!");
                sqlStatement.append(oldDeweyId);
                sqlStatement.append("!");
                sqlStatement.append(currentPathId);
                sqlStatement.append("\n");

                try {
                    if (numberRows >= 500) {
                        statementsFile.write(sqlStatement.toString());
                        sqlStatement = new StringBuilder();
                        numberRows = 0;
                        System.out.println(numberTags);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
                }

                currentPathId++;
            }
        }
        
        lastCall = TAG;
        
        deweyStack.pop();
        ascending = false;
        currentLevel--;        
        currentText = "";
    }
    
    File file;
    InputStream inputStream;
    Reader reader;
    InputSource is;            
            
    public void addFile(String path) throws FileNotFoundException, UnsupportedEncodingException {
        
        if(path == null)
            return;
 
        file = new File(path);
        inputStream = new FileInputStream(file);
        reader = new InputStreamReader(inputStream,"UTF-8");
        
        is = new InputSource(reader);
    	is.setEncoding("UTF-8");
    }
    
    
    public void run() {

        try {
            xr = XMLReaderFactory.createXMLReader();        
        } catch (SAXException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        xr.setContentHandler(this);
	xr.setErrorHandler(this);

        try {

            xr.parse(is);

        } catch (IOException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
}
